#include "HttpApi.h"

std::unordered_map<std::string, UserInfo> HttpApi::accessIds;
std::unordered_map<std::string, pid_t> HttpApi::ffmpegPid;
static std::string IP = "";

bool HttpApi::DataBaseOperation(Json::Value& responseContent,
    const Json::Value& condition, const std::string& tableName, const std::string& operation)
{
    int code;
    std::string message;

    if(operation == "Add")
    {
        DatabaseUtil::GetGetInstance()->AddItem(tableName, condition, message, code);
    }
    else if(operation == "Delete")
    {
        DatabaseUtil::GetGetInstance()->DeleteItem(tableName, condition["GUID"].asString(), message, code);
    }
    else if(operation == "Edit")
    {
        DatabaseUtil::GetGetInstance()->EditItem(tableName, condition, message, code);
    }
    else if(operation == "Query")
    {   
        Json::Value result;
        Json::Value pageInfo;
        DatabaseUtil::GetGetInstance()->QueryItems(tableName, condition, result, pageInfo, true, message, code);
        responseContent["Data"] = result;
        responseContent["PageInfo"] = pageInfo;
    }
    else
    {
        code = 400;
        message = "无效的数据库操作";
    }

    responseContent["Code"] = code;
    responseContent["Message"] = message;
    return true;
}

bool HttpApi::GetCameraFlv(Json::Value& responseContent, const Json::Value& cameraInfo)
{
    int code;
    std::string message;

    Json::Value result;
    Json::Value pageInfo;
    Json::Value condition;
    std::string cameraGuid = cameraInfo["CameraGuid"].asString();
    condition["GUID"] = cameraGuid;
    DatabaseUtil::GetGetInstance()->QueryItems("CameraConfig", condition, result, pageInfo, false, message, code);

    if(result.size() == 0)
    {
        responseContent["Code"] = 400;
        responseContent["Message"] = "未找到相关摄像头";
        return true;
    }

    std::string rtspUrl = result[0]["CameraStreamUrl"].asString();
    if(rtspUrl.empty())
    {
        responseContent["Code"] = 400;
        responseContent["Message"] = "未配置流地址";
        return true;
    }

    //若IP为空则获取一次IP
    if(IP.empty())
    {
        //获取IP地址
        std::ifstream file("./config");
        if (!file.is_open()) {
            std::cerr << "无法打开文件!" << std::endl;
            return true;
        }
        std::getline(file, IP);
        file.close();
    }

    //拼接该摄像头的流地址
    std::ostringstream pushUrl;
    std::ostringstream flvUrl;
    pushUrl << "rtmp://" << IP << "/live/" << cameraGuid;
    flvUrl << "http://" << IP << ":81/live/" << cameraGuid << ".live.flv";
    responseContent["Data"]["flvUrl"] = flvUrl.str();

    std::cout << "尝试转发视频流：" << rtspUrl << std::endl;
    std::cout << "目标流地址：" << pushUrl.str() << std::endl;

    //若不存在该摄像头的转发则新建
    if(ffmpegPid.find(cameraGuid) == ffmpegPid.end())
    {
        //新建一个ffmpeg转发进程，并纪录PID
        pid_t pid = fork();
        if(pid == 0)
        {
            execl("./ffmpeg", "./ffmpeg", "-rtsp_transport", "tcp", "-i", rtspUrl.c_str(),
                "-c:v", "copy", "-c:a", "aac", "-f", "flv", pushUrl.str().c_str(), nullptr);
            std::cout << "拉流失败" << pid << std::endl;
            exit(0);
        }
        else if (pid > 0) {
            std::cout << "摄像头视频流转发进程创建成功，进程PID:" << pid << std::endl;
        } else {
            std::cout << "摄像头视频流转发进程创建失败" << std::endl;
        }

        ffmpegPid[cameraGuid] = pid;
    }
    message = "成功获取流地址";

    responseContent["Code"] = code;
    responseContent["Message"] = message;
    return true;
}

bool HttpApi::StopCameraFlv(Json::Value& responseContent, const Json::Value& cameraInfo)
{
    std::string cameraGuid = cameraInfo["CameraGuid"].asString();

    if(ffmpegPid.find(cameraGuid) != ffmpegPid.end())
    {
        //停掉该转发的ffmpeg进程
        pid_t pid = ffmpegPid[cameraGuid];
        char command[100];
        sprintf(command, "kill -9 %d", pid);
        std::system(command);

        ffmpegPid.erase(cameraGuid);
        responseContent["Code"] = 200;
        responseContent["Message"] = "成功停止转发"; 
    }
    else
    {
        responseContent["Code"] = 400;
        responseContent["Message"] = "该摄像头未进行转发";
    }
    std::cout << "当前正在转发的视频流数量：" << ffmpegPid.size() << std::endl;

    return true;
}

bool HttpApi::LogIn(Json::Value& responseContent, const Json::Value& userData)
{
    int code;
    std::string message;

    Json::Value result;
    Json::Value condition;
    Json::Value pageInfo;
    condition["UserID"] = userData["UserID"];
    DatabaseUtil::GetGetInstance()->QueryItems("UserInfo", condition, result, pageInfo, false, message, code);

    if(result.size() == 0 || userData["UserID"].empty())
    {
        code = 400;
        message = "账户不存在";
    }
    else if(result[0]["UserPassword"] == userData["UserPassword"])
    {
        long curTime = time(0);
        std::string token = Tools::GenRandom(16);
        responseContent["Token"] = token;
        UserInfo info = {result[0]["UserID"].asString(), result[0]["UserName"].asString(), curTime};
        accessIds[token] = info;
        code = 200;
        message = "登陆成功";

        //每次有账号登陆成功时清理一下标识表，避免标识表的过期token堆太多,暂定为1天后过期
        std::vector<std::string> needRemove;
        for (auto it = accessIds.begin(); it != accessIds.end(); ++it) {
            if(it->second.lastLoginTime < curTime - 86400) needRemove.push_back(it->first);
        }

        for (const auto& key : needRemove)
        {
            accessIds.erase(key);
            std::cout << "已删除过期的token：" << key << std::endl;
        }
    }
    else
    {
        code = 400;
        message = "密码错误"; 
    }

    responseContent["Code"] = code;
    responseContent["Message"] = message;
    return true;
}

bool HttpApi::GetUser(Json::Value& responseContent, const Json::Value& condition)
{
    int code;
    std::string message;

    Json::Value result;
    Json::Value pageInfo;
    DatabaseUtil::GetGetInstance()->QueryItems("UserInfo", condition, result, pageInfo, false, message, code);

    //数据库查询错误
    if(code != 200) return false;

    //若查找的账户不存在
    if(result.size() == 0)
    {
        code = 500;
        message = "查找的账户不存在";
        return false;
    }
    
    Json::Value condition1;
    condition1["RoleCode"] = result[0]["UserRole"];
    Json::Value result1;
    DatabaseUtil::GetGetInstance()->QueryItems("RoleConfig", condition1, result1, pageInfo, false, message, code);

    //若查找的账户的角色不存在
    if(result1.size() == 0 || condition1["RoleCode"].asString().empty())
    {
        code = 500;
        message = "查找的账户的角色不存在";
    }
    else
    {
        result[0]["RoleInfo"] = result1[0];
    }
    
    responseContent["Data"] = result[0];
    responseContent["Code"] = code;
    responseContent["Message"] = message;
    return true;
}

bool HttpApi::HasAlgorithm(Json::Value& responseContent, const Json::Value& condition)
{
    int code;
    std::string message;

    Json::Value result;
    Json::Value pageInfo;
    DatabaseUtil::GetGetInstance()->QueryItems("CameraConfig", {}, result, pageInfo, false, message, code);

    Json::Value cameraInfo;
    for (unsigned int i = 0; i < result.size(); i++)
    {
        cameraInfo[i]["CameraGuid"] = result[i]["GUID"].asString();
        cameraInfo[i]["CameraName"] = result[i]["CameraName"].asString();
        if (result[i].isMember("CameraAlgorithmConfigs") && result[i]["CameraAlgorithmConfigs"].isMember(condition["AlgorithmGUID"].asString()))
        {
            
            cameraInfo[i]["Enable"] = "1";
        }
        else cameraInfo[i]["Enable"] = "0"; 
    }
    
    responseContent["Data"] = cameraInfo;
    responseContent["Code"] = code;
    responseContent["Message"] = message;
    return true;
}

bool HttpApi::UpdateAlgorithmBinding(Json::Value& responseContent, const Json::Value& data)
{
    int code;
    std::string message;

    Json::Value result;
    Json::Value pageInfo;
    DatabaseUtil::GetGetInstance()->QueryItems("CameraConfig", {}, result, pageInfo, false, message, code);

    std::string algorithmGuid = data["AlgorithmGUID"].asString();
    Json::Value bindingInfo = data["BindingInfo"];

    Json::Value bindingInfoConverted;
    for (unsigned int i = 0; i < bindingInfo.size(); i++)
    {
        bindingInfoConverted[bindingInfo[i].asString()] = "1";
    }

    for (unsigned int i = 0; i < result.size(); i++)
    {
        if(bindingInfoConverted.isMember(result[i]["GUID"].asString()))
        {
            Json::Value temp;
            temp["GUID"] = result[i]["GUID"];
            temp["CameraAlgorithmConfigs"] = result[i]["CameraAlgorithmConfigs"];
            temp["CameraAlgorithmConfigs"][algorithmGuid]["AlgorithmName"] = data["AlgorithmName"];
            temp["CameraAlgorithmConfigs"][algorithmGuid]["AlgorithmType"] = data["AlgorithmType"];
            temp["CameraAlgorithmConfigs"][algorithmGuid]["AlgorithmCode"] = data["AlgorithmCode"];
            DatabaseUtil::GetGetInstance()->EditItem("CameraConfig", temp, message, code);
        }
        else
        {
            if(result[i].isMember("CameraAlgorithmConfigs") && result[i]["CameraAlgorithmConfigs"].isMember(algorithmGuid))
            {
                Json::Value temp;
                temp["GUID"] = result[i]["GUID"];
                temp["CameraAlgorithmConfigs"] = result[i]["CameraAlgorithmConfigs"];
                temp["CameraAlgorithmConfigs"].removeMember(algorithmGuid);
                DatabaseUtil::GetGetInstance()->EditItem("CameraConfig", temp, message, code);
            }
        }
    }

    responseContent["Code"] = code;
    responseContent["Message"] = message;
    return true;
}

bool HttpApi::AlgorithmDelete(Json::Value& responseContent, const Json::Value& condition)
{
    int code;
    std::string message;

    //获取所有摄像头信息
    Json::Value result;
    Json::Value pageInfo;
    DatabaseUtil::GetGetInstance()->QueryItems("CameraConfig", {}, result, pageInfo, false, message, code);

    //判断是否有摄像头还绑定该算法
    for (unsigned int i = 0; i < result.size(); i++)
    {
        if (result[i].isMember("CameraAlgorithmConfigs") && result[i]["CameraAlgorithmConfigs"].isMember(condition["AlgorithmGUID"].asString()))
        {
            code = 400;
            message = "该算法还有摄像头绑定，无法删除";
            responseContent["Code"] = code;
            responseContent["Message"] = message;
            return true;
        }
    }

    DatabaseUtil::GetGetInstance()->DeleteItem("AlgorithmConfig", condition["AlgorithmGUID"].asString(), message, code);

    responseContent["Code"] = code;
    responseContent["Message"] = message;
    return true;
}

bool HttpApi::AlarmHandle(Json::Value& responseContent, Json::Value& data, const UserInfo& userInfo)
{
    int code;
    std::string message;

    time_t curTime = time(0);
    std::tm* timeinfo = std::localtime(&curTime);
    std::ostringstream timeStr;
    timeStr << std::put_time(timeinfo, "%Y-%m-%d %H:%M:%S");

    Json::Value GUIDs = data["GUID"];
    data["HandleUserId"] = userInfo.userID;
    data["HandleUserName"] = userInfo.userName;
    data["HandleType"] = "人工处理";
    data["HandleTime"] = timeStr.str();
    data.removeMember("GUID");

    Json::Value handleInfo;
    handleInfo["AlarmHandleInfo"] = data;
    handleInfo["AlarmStatus"] = "03";
    for (unsigned int i = 0; i < GUIDs.size(); i++)
    {
        handleInfo["GUID"] = GUIDs[i];
        DatabaseUtil::GetGetInstance()->EditItem("AlarmInfo", handleInfo, message, code);
    }

    responseContent["Code"] = code;
    responseContent["Message"] = message;
    return true;
}

bool HttpApi::AlarmExport(std::string& responseContent, const Json::Value& alarmGuids)
{
    int code;
    std::string message;

    Json::Value handleType;
    handleType["01"] = "未处理";
    handleType["02"] = "处理中";
    handleType["03"] = "已处理";

    std::ostringstream output;
    output << "报警编码,报警类型,报警等级,报警时间,报警区域,报警设备编码,报警设备名称,报警备注,报警状态,处理信息,处理结果,处理时间,处理类型,处理用户ID,处理用户名" << std::endl;
    for (unsigned int i = 0; i < alarmGuids["AlarmGuid"].size(); i++)
    {
        Json::Value result;
        Json::Value pageInfo;
        Json::Value condition;
        condition["GUID"] = alarmGuids["AlarmGuid"][i];
        DatabaseUtil::GetGetInstance()->QueryItems("AlarmInfo", condition, result, pageInfo, false, message, code);

        if(result.size() == 0) continue;

        Json::Value temp = result[0];
        output << temp["AlarmCode"].asString() << ',' << temp["AlarmType"].asString() << ',' << temp["AlarmLevel"].asString() << ','
        << temp["AlarmTime"][0].asString() << ',' << temp["AlarmPosition"].asString() << ',' << temp["AlarmDeviceCode"].asString() << ','
        << temp["AlarmDeviceName"].asString() << ','<< temp["AlarmRemark"].asString() << ','
        << handleType[temp["AlarmStatus"].asString()].asString() << ',' << temp["AlarmHandleInfo"]["HandleDetail"].asString() << ','
        << temp["AlarmHandleInfo"]["HandleResult"].asString() << ',' << temp["AlarmHandleInfo"]["HandleTime"].asString() << ','
        << temp["AlarmHandleInfo"]["HandleType"].asString() << ',' << temp["AlarmHandleInfo"]["HandleUserId"].asString() << ','
        << temp["AlarmHandleInfo"]["HandleUserName"].asString() << std::endl;
    }

    responseContent = output.str();
    return true;
}

bool HttpApi::AddAlarm(Json::Value& responseContent, Json::Value& data)
{
    int code;
    std::string message;

    data["AlarmTimeStamp"] = time(0);
    data["AlarmPicture"] = "/AlarmPic" + data["AlarmPicture"].asString();
    DatabaseUtil::GetGetInstance()->AddItem("AlarmInfo", data, message, code);

    responseContent["Code"] = code;
    responseContent["Message"] = message;
    return true;
}

bool HttpApi::GetAlarmStatistics(Json::Value& responseContent, Json::Value& data, bool isTime)
{
    int code;
    std::string message;

    long start = data["TimeStamp"][0].asInt64();
    long end = data["TimeStamp"][1].asInt64();
    long step = data["TimeStep"].asInt64();
 
    Json::Value condition;
    condition["TimeStampStart"] = start;
    condition["TimeStampEnd"] = end;
    
    Json::Value result;
    Json::Value pageInfo;
    DatabaseUtil::GetGetInstance()->QueryItems("AlarmInfo", condition, result, pageInfo, true, message, code);
    
    Json::Value statisticsResult1;
    Json::Value statisticsResult2;
    if (isTime)
    {
        for (unsigned int i = 0; i < result.size(); i++)
        {
            long timeStamp = result[i]["AlarmTimeStamp"].asInt64();
            int index = (timeStamp - start)/step;
            statisticsResult1[index] = statisticsResult1[index].asInt() + 1;
        }

        int totalNum = ceil((end - start)/((double)step));
        for (int i = 0; i < totalNum; i++)
        {
            statisticsResult2[i]["Count"] = statisticsResult1[i].asInt();

            time_t timestamp = start + step + i * step - 1;
            std::tm* timeinfo = std::localtime(&timestamp);
            char buffer[80];
            std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", timeinfo);
            statisticsResult2[i]["EndTime"] = buffer;

            statisticsResult2[i]["TimeRange"][0] = timestamp - step + 1;
            statisticsResult2[i]["TimeRange"][1] = timestamp;
        }
    }
    else
    {
        for (unsigned int i = 0; i < result.size(); i++)
        {
            std::string alarmType = result[i]["AlarmType"].asString();
            statisticsResult1[alarmType] = statisticsResult1[alarmType].asInt() + 1;
        }

        Json::Value::Members members = statisticsResult1.getMemberNames();
        int i = 0;
        for (const auto& name : members) {
            statisticsResult2[i]["AlarmType"] = name;
            statisticsResult2[i]["Count"] = statisticsResult1[name];
            i++;
        }
    }

    responseContent["Data"] = statisticsResult2;
    responseContent["Code"] = code;
    responseContent["Message"] = message;
    return true;
}

bool HttpApi::GetMenuTree(Json::Value& responseContent, const Json::Value& condition)
{
    int code;
    std::string message;

    //先查询所有存在的节点
    Json::Value result;
    Json::Value pageInfo;
    DatabaseUtil::GetGetInstance()->QueryItems("MenuConfig", {}, result, pageInfo, false, message, code);

    //查询父节点
    Json::Value resultRoot;
    Json::Value menuCondition = condition["MenuFilter"];
    DatabaseUtil::GetGetInstance()->QueryItems("MenuConfig", menuCondition, resultRoot, pageInfo, false, message, code);

    //将节点信息转换为便于访问的表
    Json::Value resultMap;
    for (unsigned int i = 0; i < result.size(); i++)
    {
        //先默认项权限设置为无
        result[i]["Enable"] = "0";
        resultMap[result[i]["MenuCode"].asString()] = result[i];
    }
    
    //若查询的是特定角色的权限
    if(condition["RoleCode"] && condition["RoleCode"] != "")
    {
        //查询该角色各个节点权限
        Json::Value result1;
        Json::Value pageInfo;
        Json::Value roleInfo;
        roleInfo["RoleCode"] = condition["RoleCode"];
        DatabaseUtil::GetGetInstance()->QueryItems("RoleConfig", roleInfo, result1, pageInfo, false, message, code);

        //若该角色存在，则对每个节点的权限进行赋值
        if(result1.size() != 0)
        {
            Json::Value rolePermission = result1[0]["RolePermission"];
            Json::Value::Members members = rolePermission.getMemberNames();
            for (const auto& name : members) 
            {
                //如果权限中有该节点且该节点为允许访问，则修改该节点的访问权限
                if(resultMap.isMember(name) && rolePermission[name] != "0")
                {
                    resultMap[name]["Enable"] = "1";
                }
            }
        }
    }

    //开始将查询结果用父节点名组合成树
    int remainCount= resultMap.size(), remainCountPre = remainCount;
    std::unordered_map<std::string, Json::Value*> preLayer;//存储当前层拥有的节点
    Json::Value result2;

    //首先创造根节点，若未指定根节点则返回全部节点
    if(condition.empty())
    {
        Json::Value::Members members = resultMap.getMemberNames();
        for (const auto& name : members) 
        {
            //如果节点父节点为0则连接至根节点
            if(resultMap[name]["MenuParentCode"] == "0" || resultMap[name]["MenuParentCode"].asString().empty())
            {
                result2[name] = resultMap[name];
                preLayer[name]= &result2[name];
                remainCount--;
                resultMap.removeMember(name);
            }
        }
    }
    else
    {
        //若指定节点则将其视为根节点
        for (unsigned int i = 0; i < resultRoot.size(); i++)
        {
            std::string nodeCode = resultRoot[i]["MenuCode"].asString();
            result2[nodeCode] = resultMap[nodeCode];
            preLayer[nodeCode]= &result2[nodeCode];
            remainCount--;
            resultMap.removeMember(nodeCode);
        }
    }
    

    //持续遍历
    while (remainCount != remainCountPre && remainCount != 0)
    {
        remainCount = resultMap.size();
        remainCountPre = remainCount;
        std::unordered_map<std::string, Json::Value*> curLayer;

        Json::Value::Members members = resultMap.getMemberNames();
        for (const auto& name : members) 
        {
            //如果节点父节点为在上一层中则连接至此
            std::string parentName = resultMap[name]["MenuParentCode"].asString();
            if(preLayer.find(parentName) != preLayer.end())
            {
                (*preLayer[parentName])["children"][name] = resultMap[name];
                curLayer[name]= &(*preLayer[parentName])["children"][name];
                remainCount--;
                resultMap.removeMember(name);
            }
        }

        preLayer = curLayer;
    }

    responseContent["Data"] = result2;
    responseContent["Code"] = code;
    responseContent["Message"] = message;
    return true;
}

bool HttpApi::GetAreaTree(Json::Value& responseContent, const Json::Value& condition)
{
    int code;
    std::string message;

    //先查询所有存在的节点
    Json::Value result;
    Json::Value pageInfo;
    DatabaseUtil::GetGetInstance()->QueryItems("AreaConfig", {}, result, pageInfo, false, message, code);

    Json::Value resultRoot;
    DatabaseUtil::GetGetInstance()->QueryItems("AreaConfig", condition, resultRoot, pageInfo, false, message, code);

    //将节点信息转换为便于访问的表
    Json::Value resultMap;
    for (unsigned int i = 0; i < result.size(); i++)
    {
        resultMap[result[i]["AreaCode"].asString()] = result[i];
    }

    //开始将查询结果用父节点名组合成树
    int remainCount= resultMap.size(), remainCountPre = remainCount;
    std::unordered_map<std::string, Json::Value*> preLayer;//存储当前层拥有的节点
    Json::Value result2;

    //首先创造根节点，若未指定根节点则返回全部节点
    if(condition.empty())
    {
        Json::Value::Members members = resultMap.getMemberNames();
        for (const auto& name : members) 
        {
            //如果节点父节点为根节点则连接至根节点，根节点默认为“0”
            if(resultMap[name]["AreaParent"] == "0" || resultMap[name]["AreaParent"].asString().empty())
            {
                result2[name] = resultMap[name];
                preLayer[name]= &result2[name];
                remainCount--;
                resultMap.removeMember(name);
            }
        }
    }
    else
    {
        //若指定节点则将其视为根节点
        for (unsigned int i = 0; i < resultRoot.size(); i++)
        {
            std::string nodeCode = resultRoot[i]["AreaCode"].asString();
            result2[nodeCode] = resultMap[nodeCode];
            preLayer[nodeCode]= &result2[nodeCode];
            remainCount--;
            resultMap.removeMember(nodeCode);
        }
    }

    //持续遍历
    while (remainCount != remainCountPre && remainCount != 0)
    {
        remainCount = resultMap.size();
        remainCountPre = remainCount;
        std::unordered_map<std::string, Json::Value*> curLayer;

        Json::Value::Members members = resultMap.getMemberNames();
        for (const auto& name : members) 
        {
            //如果节点父节点为在上一层中则连接至此
            std::string parentName = resultMap[name]["AreaParent"].asString();
            if(preLayer.find(parentName) != preLayer.end())
            {
                (*preLayer[parentName])["children"][name] = resultMap[name];
                curLayer[name]= &(*preLayer[parentName])["children"][name];
                remainCount--;
                resultMap.removeMember(name);
            }
        }

        preLayer = curLayer;
    }

    responseContent["Data"] = result2;
    responseContent["Code"] = code;
    responseContent["Message"] = message;
    return true;
}

bool HttpApi::GetAlarmImage(std::string& image, const std::string& imagePath, std::string& contentType)
{
    if(!fileExists(imagePath))
    {
        std::cout << "报警图片不存在" << std::endl;
        return false;
    }

    contentType = getContentType(imagePath);
    image = readFile(imagePath);

    return true;
}

std::string HttpApi::getContentType(const std::string &path)
{
    std::string pathEnd;
    for (size_t i = path.length(); i >=0; i--)
    {
        if(path[i] == '.')
        {
            pathEnd = path.substr(i, path.length());
            break;
        }
    }

    if(pathEnd == ".html") return "text/html";
    if(pathEnd == ".css") return "text/css";
    if(pathEnd == ".js") return "application/javascript";
    if(pathEnd == ".png") return "image/png";
    if(pathEnd == ".jpg") return "image/jpeg";
    if(pathEnd == ".jpeg") return "image/jpeg";
    if(pathEnd == ".gif") return "image/gif";
    return "text/plain";
}

std::string HttpApi::readFile(const std::string &path)
{
    //创建一个输入文件流对象，以二进制模式打开指定路径的文件
    std::ifstream file(path,std::ios::binary);

    //检查文件是否成功打开
    if(!file.is_open())
    {
        perror("file open failed");
        return "";
    }

    //将字符串流的内容转换为std::string并返回
    std::ostringstream ss;
    ss << file.rdbuf();
    return ss.str();
}

bool HttpApi::fileExists(const std::string &path)
{
    struct stat buffer;
    return stat(path.c_str(), &buffer)==0;
}